#pragma once
#include "Comm.hpp"
#include <iostream>
using namespace LogModule;
using namespace MypthreadModule;

#define DEFAULTBACKLOG 5

using fun_t = std::function<std::string(const std::string &, InterAddr &)>;
using task_t = std::function<void()>;

/*
    TCP
    [1] 初始化
        1. 创建监听套接字 --> 用于监听链接请求
        2. 绑定指定的Server端的端口号和IP地址
        3. 设置监听状态
    [2] 启动
        1. 从监听套接字accept获取连接 (持续性获取)
        2. 根据提供服务的要求(长服务/短服务) 实现不同的版本(多进程/多线程/线程池)
        3. 通过不同版本去执行服务Server
    [3] 服务
        1. 读取来自Client端的消息
        2. 通过回调函数处理消息
        3. 向Client发回消息
*/

/* 服务器禁止Copy --> 使用继承NoCopy实现 */
class TCPServer : public NoCopy
{
public:
    TCPServer(const uint16_t &port, fun_t func)
        : _listenSockfd(-1),
          _port(port),
          _isrunning(false),
          _func(func)
    {
    }

    // 服务
    void Server(const int sockfd, InterAddr peer)
    {
        while (true)
        {
            /* 1. 读取来自Client端的消息 */
            //     a. n > 0: 读取成功
            //     b. n < 0: 读取失败
            //     c. n == 0: Client端把链接关闭了，读到了文件的结尾
            std::cout <<__FILE__<<__LINE__<< "sockfd: " << sockfd << std::endl;
            char buffer[1024];
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                LOG(LogLevel::INFO) << "Get Client message: " << peer.AddrName();

                /* 2. 通过回调函数处理消息 */
                std::string echo_string = _func(buffer, peer);

                /* 3. 向Client发回消息 */
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << peer.AddrName() << " 退出了...";
                close(sockfd);
                break;
            }
            else if (n < 0)
            {
                perror("异常了: \n");
                // LOG(LogLevel::FATAL) << peer.AddrName() << " 异常了...";
                close(sockfd);
                break;
            }
        }
    }

    // 初始化
    void Init()
    {
        /* 1. 创建监听套接字 --> 用于监听链接请求 */
        _listenSockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenSockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error!";
            exit(SOCK_ERR);
        }
        LOG(LogLevel::INFO) << "socket success! " << _listenSockfd;

        /* 2. 绑定指定的Server端的端口号和IP地址 */
        InterAddr local(_port);
        int n = bind(_listenSockfd, CONV(&local.GetAddr()), local.Len());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error!";
            exit(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success! " << _listenSockfd;

        /* 3. 设置监听状态 */
        int m = listen(_listenSockfd, DEFAULTBACKLOG);
        if (m < 0)
        {
            LOG(LogLevel::FATAL) << "listen error!";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success! " << _listenSockfd;
    }

    // version-1 多进程
    void VersionProcess(const int sockfd, InterAddr &peer)
    {
        pid_t id = fork();
        if (id == 0)
        {
            // child process
            // 1. 关闭子进程不需要的_listenSockfd
            close(_listenSockfd);
            /* 使用孙子进程，退出子进程，让孙子进程成为孤儿进程由 1 号进程接管 */
            if (fork() > 0)
                exit(OK);
            // 孙子进程
            Server(sockfd, peer);
            exit(OK);
        }
        else if (id > 0)
        {
            // father process
            // 关闭sockfd
            close(sockfd);
            // 解决父进程等待子进程, 解决子进程的僵尸状态
            pid_t rid = waitpid(id, nullptr, 0); // 会阻塞的吗？不会，因为子进程立马退出了
            (void)rid;
        }
        else
        {
            // error
            LOG(LogLevel::FATAL) << "fork error!";
            exit(FORK_ERR);
        }
    }

    // 运行
    void Run()
    {
        _isrunning = true;
        while (_isrunning)
        {
            /* 1. 从监听套接字accept获取连接 (持续性获取) */
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenSockfd, CONV(&peer), &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::WARING) << "accept error!  "<<strerror(errno);
                continue;
            }
            InterAddr addr(peer);
            LOG(LogLevel::INFO) << "accept success! " << addr.AddrName();

            /* 2. 根据提供服务的要求(长服务/短服务) 实现不同的版本(多进程/多线程/线程池) */
            // version-1 多进程-长服务
            // VersionProcess(sockfd, addr);

            // version-2 多线程-长服务
            LOG(LogLevel::INFO) << "1. sockfd: " << sockfd; // 正常的
            std::thread t([this, sockfd, addr](){
                LOG(LogLevel::INFO) << "开始执行任务";
                LOG(LogLevel::INFO) << "2. sockfd: " << sockfd;
                this->Server(sockfd, addr);
            });
            t.detach(); // 分离线程
            

            // version-3 线程池-短任务(如果实现的是长服务可能会导致线程池阻塞，其他客户端要想调用必须等待前面的客户端退出！)
            // ThreadPoolModule::ThreadPool<task_t>::GetInstance()->Enqueue([this, sockfd, addr](){
            //         LOG(LogLevel::INFO) << "开始执行任务";
            //         this->Server(sockfd, addr);
            // });
            sleep(1000);
        }
        _isrunning = false;
    }

    ~TCPServer()
    {
    }

private:
    int _listenSockfd; /* 监听套接字 */
    uint16_t _port;    /* 端口号 */
    bool _isrunning;   /* 服务器状态 */
    fun_t _func;       /* 回调函数 */
};